﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Media;
using System.Timers;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Spelprojekt
{
    /// <summary>
    /// Huvudklassen för spelet.
    /// </summary>
    public class FTD : Microsoft.Xna.Framework.Game
    {
#region Medlemsvariabler
        SpriteFont Score;
        SpriteFont Lives;
        Vector2 LifeTextPos;
        Vector2 ScoreTextPos;
        Texture2D backgroundTexture;
        Texture2D Gt, At, Mt, Et1, Ot, Vt, Et2, Rt;
        Rectangle GRec = new Rectangle(20, -100, 90, 90);
        Rectangle ARec = new Rectangle(100, -140, 90, 90);
        Rectangle MRec = new Rectangle(180, -180, 90, 90);
        Rectangle E1Rec = new Rectangle(260, -220, 90, 90);
        Rectangle ORec = new Rectangle(450, -260, 90, 90);
        Rectangle VRec = new Rectangle(530, -300, 90, 90);
        Rectangle E2Rec = new Rectangle(610, -340, 90, 90);
        Rectangle RRec = new Rectangle(690, -380, 90, 90);
        private int overGame = 1;
        private int overGameResetingAdder = -20;
        Texture2D PlayerTexture;
        Texture2D BoxTexture;
        Texture2D GhostTexture;
        Texture2D MonsterTexture;
        Texture2D ProjectileTexture;
        Texture2D SpiderTexture;
        Texture2D Bana1Texture;
        Texture2D Bana2Texture;
        Rectangle Bana1Rectangle = new Rectangle(0, 0, 800, 500);
        Rectangle Bana2Rectangle = new Rectangle(800, 0, 800, 500);
        GraphicsDevice device;
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        int screenWidth;
        int screenHeight;
        MysteryBox box1 = new MysteryBox();
        Player Gura;
        Monsters monsts;
        Ghosts ghosts;
        Spiders spindlar;
        Timer SpecialShootingTime = new Timer(7000);
        Timer GhostAdderTime = new Timer(10000);
#endregion Medlemsvariabler
        public FTD()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Initialisering utav skärmen.
        /// </summary>
        protected override void Initialize()
        {
            // Initialisering
            graphics.PreferredBackBufferWidth = 800;
            graphics.PreferredBackBufferHeight = 500;
            graphics.IsFullScreen = false;
            graphics.ApplyChanges();
            base.Initialize();
        }

        /// <summary>
        /// Har laddas det in objekt samt texturer
        /// och bilder in.
        /// </summary>
        protected override void LoadContent()
        {
            
            spriteBatch = new SpriteBatch(GraphicsDevice);
            device = graphics.GraphicsDevice;

            Gura = new Player();
            ghosts = new Ghosts();
            monsts = new Monsters();
            spindlar = new Spiders();
            

            Score = Content.Load<SpriteFont>("Score");
            Lives = Content.Load<SpriteFont>("Lives");
          
            ScoreTextPos = new Vector2(10, 20);
            LifeTextPos = new Vector2(670, 20);

            backgroundTexture = Content.Load<Texture2D>("Background");
            LoadingTextureForObjects();
            LoadingTextureForGameOver();

            screenWidth = device.PresentationParameters.BackBufferWidth;
            screenHeight = device.PresentationParameters.BackBufferHeight;
        }

        /// <summary>
        /// Unload Content: Denna använder jag ej. 
        /// </summary>
        protected override void UnloadContent()
        {
        }

        /// <summary>
        /// Här sker updateringen utav spelet i realtid. Här anropas
        /// funktioner som behövs för att byta nivå, kolla om en Mysterybox är tagen,
        /// om man får "specialskjutning". 
        /// Om Escape trycks ned avbryts programmet.
        /// </summary>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            KeyboardState Keystate = Keyboard.GetState();
            Bana1Texture = Content.Load<Texture2D>("Bana1");
            Bana2Texture = Content.Load<Texture2D>("Bana2");
            LoadingTextureForObjects();
            //Escape-key
            if (Keystate.IsKeyDown(Keys.Escape))
                this.Exit();
            if (Gura.life > 0)
            {
                ghosts.MoveAndAdd();
                Gura.Act();
                if (Gura.points > 10)
                {
                    box1.Move();
                }

                LevelSwitch();

                SpecialShootingTime.Elapsed += new ElapsedEventHandler(Gura.killTripleshoot);
                SpecialShootingTime.Elapsed += new ElapsedEventHandler(Gura.killSprayshoot);

                BoxTaking();
                //Console.WriteLine("Points: ", Gura.points);
            }
            else
            {
                Gura.life = 0;
                Death();
                GameOverVisual();
            }
            base.Update(gameTime);
        }

        /// <summary>
        /// Huvudsakliga utritningsfunktionen som baseras på programtiden.
        /// Jag har delat upp Draw i flera sub-funktioner som sköter utskrift
        /// för varje ubjekttyp.
        /// </summary>
#region Drawing
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin();
            DrawStart();
            DrawLane();
            if(Gura.life > 0)
                DrawBox();
            DrawProjectiles();
            DrawPlayer();
            DrawGhosts();
            DrawMonsters();
            DrawSpiders();
            DrawText();
            if (Gura.life <= 0)
                DrawEnd();
            spriteBatch.End();

            base.Draw(gameTime);
        }
        /*! Anropas i <B>Draw</B> för utritningen utav <B>bakgrunden</B> i spelet. */
        protected void DrawStart() 
        {
            Rectangle screenRectangle = new Rectangle(0, 0, screenWidth, screenHeight);
            spriteBatch.Draw(backgroundTexture, screenRectangle, Color.White);

        }
        /*! Anropas i <B>Draw</B> för utritningen utav <B>spelaren</B> i spelet. */
        protected void DrawPlayer()
        {
            spriteBatch.Draw(PlayerTexture, Gura.pRec, Color.White);

        }
        /*! Anropas i <B>Draw</B> för utritningen utav <B>Mysterybox-objektet</B> i spelet. */
        protected void DrawBox()
        {
            spriteBatch.Draw(BoxTexture, box1.boxRec, Color.White);
        }
        /*! Anropas i <B>Draw</B> för utritningen utav alla <B>spöken</B>. Funktionen kollar dessutom om spökena kolliderar med spelaren och drar i dylikt fall bort ett liv ifrån spelaren samt dödar(tar bort från listan) det aktuella spöket. Om den kolliderar med en projektil dör den också. Detta kollas även här. */
        protected void DrawGhosts()
        {
            for (int i = 0; i < ghosts.ghostList.Count(); i++)
            {
                if (!ghosts.ghostList[i].dead)
                {
                    if (Gura.pRec.Intersects(ghosts.ghostList[i].GhostRectangle))
                    {
                        Gura.life--;
                        ghosts.ghostList[i].dead = true;
                        break;
                    }
                    spriteBatch.Draw(GhostTexture, ghosts.ghostList[i].GhostRectangle, Color.White);
                    for (int x = 0; x < Gura.projectiles.Count(); x++)
                    {
                        if (ghosts.ghostList[i].GhostRectangle.Intersects(Gura.projectiles[x].projRec))
                        {
                            Gura.projectiles.RemoveAt(x);
                            ghosts.ghostList[i].dead = true;
                            if(Gura.life > 0)
                                Gura.points++;
                            break;
                        }
                    }
                }
            }
        }
        /*! Anropas i <B>Draw</B> för utritningen utav alla <B>spindlar</B>. Funktionen kollar dessutom om spindlarna kolliderar med spelaren och drar i dylikt fall bort ett liv ifrån spelaren samt dödar(tar bort från listan) det aktuella spindeln. Om den kolliderar med en projektil dör den också. Detta kollas även här. */
        protected void DrawSpiders()
        {
            for (int i = 0; i < spindlar.spiderList.Count(); i++)
            {
                if (!spindlar.spiderList[i].dead)
                {
                    if (Gura.pRec.Intersects(spindlar.spiderList[i].SpiderRectangle))
                    {
                        Gura.life--;
                        spindlar.spiderList[i].dead = true;
                        break;
                    }
                    spriteBatch.Draw(SpiderTexture, spindlar.spiderList[i].SpiderRectangle, Color.White);
                    for (int x = 0; x < Gura.projectiles.Count(); x++)
                    {
                        if (spindlar.spiderList[i].SpiderRectangle.Intersects(Gura.projectiles[x].projRec))
                        {
                            Gura.projectiles.RemoveAt(x);
                            spindlar.spiderList[i].dead = true;
                            if (Gura.life > 0)
                                Gura.points++;
                            break;
                        }
                    }
                }
            }
        }
        /*! Anropas i <B>Draw</B> för utritningen utav alla <B>monster</B>. Funktionen kollar dessutom om monstrena kolliderarmed spelaren och drar i dylikt fall bort ett liv ifrån spelaren samt dödar(tar bort från listan) det aktuella monstret. Om den kolliderar med en projektil dör den också. Detta kollas även här. */
        protected void DrawMonsters()
        {
            for (int i = 0; i < monsts.monsterList.Count(); i++)
            {
                if (!monsts.monsterList[i].dead)
                {
                    if (Gura.pRec.Intersects(monsts.monsterList[i].MonstRectangle))
                    {
                        Gura.life--;
                        monsts.monsterList[i].dead = true;
                    }
                    spriteBatch.Draw(MonsterTexture, monsts.monsterList[i].MonstRectangle, Color.White);
                    for (int x = 0; x < Gura.projectiles.Count(); x++)
                    {
                        if (monsts.monsterList[i].MonstRectangle.Intersects(Gura.projectiles[x].projRec))
                        {
                            Gura.projectiles.RemoveAt(x);
                            monsts.monsterList[i].life--;
                            if (monsts.monsterList[i].life <= 0)
                            {
                                monsts.monsterList[i].dead = true;
                            }
                            if (Gura.life > 0)
                                Gura.points++;
                            break;
                        }
                    }
                }
            }
        }
        /*! Anropas i <B>Draw</B> för utritningen utav alla <B>projektiler</B>.*/
        protected void DrawProjectiles()
        {
            for (int i = 0; i < Gura.projectiles.Count(); i++)
            {
                spriteBatch.Draw(ProjectileTexture, Gura.projectiles[i].projRec, Color.White);
            }
        }
        /*! Anropas i <B>Draw</B> för utritningen utav <B>spelbanan</B>. Den uppdateras/flyttas även här. Bakgrunden består utav <B>två bilder</B> som flyttas hela tiden.*/
        protected void DrawLane()
        {

            spriteBatch.Draw(Bana1Texture, Bana1Rectangle, Color.White);
            spriteBatch.Draw(Bana2Texture, Bana2Rectangle, Color.White);

            if (Bana1Rectangle.X <= -800)
                Bana1Rectangle.X = 800;
            if (Bana2Rectangle.X <= -800)
                Bana2Rectangle.X = 800;

            Bana1Rectangle.X--;
            Bana2Rectangle.X--;
            if (Gura.pLevel > 4)
            {
                Bana1Rectangle.X -= 2;
                Bana2Rectangle.X -= 2;
            }
            if (Gura.pLevel > 7)
            {
                Bana1Rectangle.X -= 2;
                Bana2Rectangle.X -= 2;
            }
            if (Gura.points > 500)
            {
                Bana1Rectangle.X -= 2;
                Bana2Rectangle.X -= 2;
            }

        }
        /*! Anropas i <B>Draw</B> för utritningen utav den relevanta <B>speltexten</B>. Detta är <B>poäng</B> samt spelarens <B>liv</B> .*/
        protected void DrawText()
        {
            string scoreString = "Score: " + Gura.points;
            string lifeString = "Lives: " + Gura.life;

            Vector2 textOrigin;
            textOrigin.X = 0;
            textOrigin.Y = 0;

            if (Gura.life > 1)
                spriteBatch.DrawString(Lives, lifeString, LifeTextPos, Color.DarkSlateBlue, 0, textOrigin, 1.0f, SpriteEffects.None, 0.5f);
            else
                spriteBatch.DrawString(Lives, lifeString, LifeTextPos, Color.Red, 0, textOrigin, 1.0f, SpriteEffects.None, 0.5f);
            if (Gura.life < 1 && ScoreTextPos.X < 250)
            {
                ScoreTextPos.X += 4;
                ScoreTextPos.Y += 2;
            }
            spriteBatch.DrawString(Score, scoreString, ScoreTextPos, Color.DarkSlateBlue, 0, textOrigin, 1.0f, SpriteEffects.None, 0.5f);
        }
        /*! Anropas i <B>Draw</B> för utritningen utav <B>"GAME OVER"</B> vid spelarens död.*/
        protected void DrawEnd()
        {
            spriteBatch.Draw(Gt, GRec, Color.White);
            spriteBatch.Draw(At, ARec, Color.White);
            spriteBatch.Draw(Mt, MRec, Color.White);
            spriteBatch.Draw(Et1, E1Rec, Color.White);
            spriteBatch.Draw(Ot, ORec, Color.White);
            spriteBatch.Draw(Vt, VRec, Color.White);
            spriteBatch.Draw(Et2, E2Rec, Color.White);
            spriteBatch.Draw(Rt, RRec, Color.White);

        }
#endregion Drawing
        /*! Anropas i <B>Update</B> för att se ifall spelaren tar en <B>Mysterybox</B>. Bool:en <B>box.hitMove</B> används för att sakerna i funktionen enbart skall utföras <B>en</B> gång per tillfälle då boxen tas.*/
        protected void BoxTaking()
        {
            if (box1.boxRec.Intersects(Gura.pRec) && !box1.hitMove)
            {
                box1.hitMove = true;
                SpecialShootingTime.Stop();
                SpecialShootingTime.Start();
                Random slump = new Random();
                int slumpen = slump.Next(0, 2);
                if (slumpen == 1)
                    Gura.Tripleshoot = true;
                else
                    Gura.Sprayshoot = true;

            }

        }
        /*! Anropas i <B>Update</B>  samt <B>Load</B> för att ladda in Game Over -texturerna*/
        protected void LoadingTextureForGameOver()
        {
            Gt = Content.Load<Texture2D>("G");
            At = Content.Load<Texture2D>("A");
            Mt = Content.Load<Texture2D>("M");
            Et1 = Content.Load<Texture2D>("E");
            Ot = Content.Load<Texture2D>("O");
            Vt = Content.Load<Texture2D>("V");
            Et2 = Content.Load<Texture2D>("E");
            Rt = Content.Load<Texture2D>("R");
        }
        /*! Anropas i <B>Update</B>  samt <B>Load</B> för att ladda in Objekt-texturerna*/
        protected void LoadingTextureForObjects()
        {
            PlayerTexture = Content.Load<Texture2D>(Gura.PlayerPicture);
            ProjectileTexture = Content.Load<Texture2D>("projectile");
            GhostTexture = Content.Load<Texture2D>("Ghost2");
            MonsterTexture = Content.Load<Texture2D>("Monster1");
            BoxTexture = Content.Load<Texture2D>("Mysterybox");
            SpiderTexture = Content.Load<Texture2D>("spider");
        }
        /*! Anropas i <B>Update</B> för att byta nivå/ändra förutsättningar.*/
        protected void LevelSwitch() 
        {
            if (Gura.points > 20 || Gura.pLevel >= 2) //Switching to Level 2
            {
                if (Gura.pLevel == 1)
                    Gura.pLevel = 2;
                monsts.MoveAndAdd();
            }
            if (Gura.points > 40 || Gura.pLevel >= 2) 
            {
                spindlar.MoveAndAdd();
                if (Gura.pLevel == 2) //Switching to Level 3
                {
                    box1.reSet();
                    Gura.pLevel = 3;
                    spindlar.newSpiderGeneratingPos = 770;
                }
            }
            if (Gura.points > 60 && Gura.pLevel == 3) //Switching to Level 4
            {
                box1.reSet();
                Gura.pLevel = 4;
                spindlar.newSpiderGeneratingPos = 778;
                monsts.newMonsterGeneratingPos = 600;
            }
            if (Gura.points > 80 && Gura.pLevel == 4) //Switching to Level 5
            {
                box1.reSet();
                Gura.pLevel = 5;
                spindlar.newSpiderGeneratingPos = 790;
                monsts.newMonsterGeneratingPos = 650;
            }
            if (Gura.points > 120 && Gura.pLevel == 5)
            {
                box1.reSet();
                Gura.pLevel = 6;
            }
            if (Gura.points > 150 && Gura.pLevel == 6)
            {
                box1.reSet();
                Gura.pLevel = 7;
                monsts.newMonsterGeneratingPos = 690;
                ghosts.newGhostGeneratingPos = 300;
            }
            if (Gura.points > 180 && Gura.pLevel == 7)
            {
                box1.reSet();
                Gura.pLevel = 8;
                monsts.newMonsterGeneratingPos = 690;
                spindlar.newSpiderGeneratingPos = 795;
                ghosts.newGhostGeneratingPos = 300;
            }
            if (Gura.points > 300 && Gura.pLevel == 8)
            {
                box1.reSet();
                Gura.pLevel = 9;
            }
            if (Gura.points > 400 && Gura.pLevel == 9)
            {
                box1.reSet();
                Gura.pLevel = 10;
            }
            if (Gura.points > 600 && Gura.pLevel == 10)
            {
                box1.reSet();
                Gura.pLevel = 11;
            }

        }
        /*! Anropas i <B>Update</B> vid Game Over för att visualisera objektens död. Består i sin tur utav inbyggda Dropdead-funktioner i varje objekt.*/
        protected void Death()
        {
            Gura.DropDead();
            ghosts.DropDead();
            monsts.DropDead();
            spindlar.DropDead();
        }
        /*! Anropas i <B>Update</B> vid Game Over för att flytta GAME OVER bokstäverna på rätt sätt.*/
        protected void GameOverVisual()
        {
            if (GRec.Y < 385)
            {
                GRec.Y += overGame;
            }
            if (ARec.Y < 385)
            {
                ARec.Y += overGame;
            }
            if (MRec.Y < 385)
            {
                MRec.Y += overGame;
            }
            if (E1Rec.Y < 385)
            {
                E1Rec.Y += overGame;
            }
            if (ORec.Y < 385)
            {
                ORec.Y += overGame;
            }
            if (VRec.Y < 385)
            {
                VRec.Y += overGame;
            }
            if (E2Rec.Y < 385)
            {
                E2Rec.Y += overGame;
            }
            if (RRec.Y < 385)
            {
                RRec.Y += overGame;
            }

            if (overGame > 20)
            {
                overGame = overGameResetingAdder;
                overGameResetingAdder += 5;
            }
            overGame ++;

        }
    }
}
